﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

using Microsoft.Win32;

using MVPlan.Engine;
using MVPlan.Engine.Dive;
using MVPlan.Engine.Gases;
using MVPlan.Engine.Modeling;
using MVPlan.Engine.Segment;
using Infragistics.Windows.Editors;
using Infragistics.Windows.Ribbon;
using Infragistics.Excel;
using System.Windows.Markup;

namespace OneStop.UI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : XamRibbonWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            this.RecentFiles = new RecentFileCollection();


        }

        #region Properties

        protected bool ResetData { get; set; }

        #endregion

        #region Initialise GUI

        protected void Initialize()
        {
            Main.Reset(false);
            Main.chkOCDeco.IsChecked = Prefs.Current.OcDeco;
            Main.IsPrimaryView = true;

            //RibbonTabItem settings = Ribbon.Tabs[1];

            //RibbonGroup gf = (RibbonGroup)settings.RibbonGroups[0];

            //ButtonGroup b = (ButtonGroup)gf.Items[0];

            //TextEditorTool txtGFLow = (TextEditorTool)b.Children[1];
            //TextEditorTool txtGFHigh = (TextEditorTool)b.Children[2];

            txtGFLow.Text = (Prefs.Current.GfLow * 100).ToString("F0");
            txtGFHigh.Text = (Prefs.Current.GfHigh * 100).ToString("F0");

            //ButtonGroup b1 = (ButtonGroup)gf.Items[1];

            //TextEditorTool txtGFLowBail = (TextEditorTool)b1.Children[1];
            //TextEditorTool txtGFHighBail = (TextEditorTool)b1.Children[2];

            txtGFLowBail.Text = (Prefs.Current.GfLowBailout * 100).ToString("F0");
            txtGFHighBail.Text = (Prefs.Current.GfHighBailout * 100).ToString("F0");

            //RibbonGroup deco = (RibbonGroup)settings.RibbonGroups[1];

            //ButtonGroup b2 = (ButtonGroup)deco.Items[0];

            //TextEditorTool txtStopIncrement = (TextEditorTool)b2.Children[1];

            //ButtonGroup b3 = (ButtonGroup)deco.Items[1];
            //TextEditorTool txtStopLast = (TextEditorTool)b3.Children[1];

            txtStopIncrement.Text = Prefs.Current.StopDepthIncrement.ToString("F0");
            txtStopLast.Text = Prefs.Current.LastStopDepth.ToString("F0");

            //ButtonGroup b4 = (ButtonGroup)deco.Items[3];

            //TextEditorTool txtStopTime = (TextEditorTool)b4.Children[1];

            txtStopTime.Text = Prefs.Current.StopTimeIncrement.ToString("F0");

            //RibbonGroup gas = (RibbonGroup)settings.RibbonGroups[2];

            //ButtonGroup bg1 = (ButtonGroup)gas.Items[0];

            //TextEditorTool txtRMVDive = (TextEditorTool)bg1.Children[1];

            //ButtonGroup bg2 = (ButtonGroup)gas.Items[1];
            //TextEditorTool txtRMVDeco = (TextEditorTool)bg2.Children[1];

            txtRMVDive.Text = Prefs.Current.RMVDive.ToString("F0");
            txtRMVDeco.Text = Prefs.Current.RMVDeco.ToString("F0");

            //RibbonGroup options = (RibbonGroup)settings.RibbonGroups[3];

            //CheckBoxTool chkRuntimeFlag = (CheckBoxTool)options.Items[0];

            chkRuntimeFlag.IsChecked = Prefs.Current.RuntimeFlag;

            //ButtonGroup og1 = (ButtonGroup)options.Items[1];

            //RadioButtonTool rdoMetric = (RadioButtonTool)og1.Children[0];
            //RadioButtonTool rdoImperial = (RadioButtonTool)og1.Children[1];

            rdoMetric.IsChecked = (Prefs.Current.Units == Units.Metric);
            rdoImperial.IsChecked = (Prefs.Current.Units == Units.Imperial);

            //ButtonGroup og2 = (ButtonGroup)options.Items[3];

            //TextEditorTool txtDescent = (TextEditorTool)og2.Children[1];

            //ButtonGroup og3 = (ButtonGroup)options.Items[4];
            //TextEditorTool txtAscent = (TextEditorTool)og3.Children[1];

            txtDescent.Text = Prefs.Current.DescentRate.ToString("F0");
            txtAscent.Text = (Prefs.Current.AscentRate * -1).ToString("F0");

            //ButtonGroup og5 = (ButtonGroup)options.Items[7];
            //TextEditorTool txtMaxPPO2 = (TextEditorTool)og5.Children[1];

            txtMaxPPO2.Text = Prefs.Current.PPO2Max.ToString("F2");


            //ButtonGroup ogsp5 = (ButtonGroup)options.Items[8];
            //TextEditorTool txtSetpointDefault = (TextEditorTool)ogsp5.Children[1];

            txtSetpointDefault.Text = Prefs.Current.SetpointDefault.ToString("F2");

            //RibbonGroup tables = (RibbonGroup)settings.RibbonGroups[4];

            //CheckBoxTool rdoShowBailout = (CheckBoxTool)tables.Items[0];
            chkShowBailout.IsChecked = Prefs.Current.ReportShowBailout;
            
            //CheckBoxTool rdoShowStopTime = (CheckBoxTool)tables.Items[1];
            chkShowStopTime.IsChecked = Prefs.Current.ReportShowStopTime;

            //RibbonTabItem warnings = Ribbon.Tabs[2];

            //RibbonGroup rPPO2 = (RibbonGroup)warnings.RibbonGroups[0];

            //ButtonGroup wg0 = (ButtonGroup)rPPO2.Items[0];

            //TextEditorTool txtWarnLowPPO2 = (TextEditorTool)wg0.Children[1];
            //TextEditorTool txtWarnHighPPO2 = (TextEditorTool)wg0.Children[2];

            txtWarnLowPPO2.Value = Prefs.Current.WarningPPO2Min.ToString("F2");
            txtWarnHighPPO2.Value = Prefs.Current.WarningPPO2Max.ToString("F2");

            //ButtonGroup wg1 = (ButtonGroup)rPPO2.Items[1];

            //TextEditorTool txtWarnDecoLow = (TextEditorTool)wg1.Children[1];
            //TextEditorTool txtWarnDecoHigh = (TextEditorTool)wg1.Children[2];

            txtWarnDecoLow.Value = Prefs.Current.WarningOptimalDecoPPO2Min.ToString("F2");
            txtWarnDecoHigh.Value = Prefs.Current.WarningOptimalDecoPPO2Max.ToString("F2");

            //RibbonGroup rPPN2 = (RibbonGroup)warnings.RibbonGroups[1];

            //ButtonGroup wg3 = (ButtonGroup)rPPN2.Items[0];

            //TextEditorTool txtWarnPPN2 = (TextEditorTool)wg3.Children[1];

            txtWarnPPN2.Value = (Prefs.Current.WarningPPN2SpikePercentageMin * 100).ToString("F0");
        }

        #endregion

        #region Ribbon Events

        private void btnNew_Click(object sender, RoutedEventArgs e)
        {
            Main.LoadFile(AppDomain.CurrentDomain.BaseDirectory + @"ProfileData\Defaults.xml");
            Initialize();
            this.RecentFiles.AddPath(Main.Path);
            setRecentFilesList();
        }

        private void btnOpen_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();

            open.Filter = "(*.xml)|*.xml";
            open.Multiselect = false;

            if (open.ShowDialog(this) == true)
            {
                Main.LoadFile(open.FileName);
                this.Title = Main.Path;
                
                this.RecentFiles.AddPath(Main.Path);
                setRecentFilesList();
            }
        }

        private void setRecentFilesList()
        {
            Ribbon.ApplicationMenu.RecentItems.Clear();
            
            for (int i = 0; i < this.RecentFiles.Count; i++)
            {
                RecentFile r = this.RecentFiles[i];
                ButtonTool b = new ButtonTool();

                b.Caption = r.FileName;
                b.Tag = r;

                b.Click += new RoutedEventHandler(RecentItem_Click);

                Ribbon.ApplicationMenu.RecentItems.Add(b);
            }
        }

        void RecentItem_Click(object sender, RoutedEventArgs e)
        {
            ButtonTool b = (ButtonTool)e.Source;
            RecentFile r = (RecentFile)b.Tag;

            if (File.Exists(r.Path))
            {
                Main.LoadFile(r.Path);
            }
            else
            {
                MessageBox.Show("File no longer exists");
            }
        }
        
        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            XamRibbonWindow_Unloaded(this, null);
        }

        private void abtSaveAs_Click(object sender, RoutedEventArgs e)
        {
            string path = GetSaveFilePath();

            if (path != null)
            {
                SaveFile(path);
            }
        }

        protected void SaveFile(string path)
        {
            Main.Path = path;

            XElement prefs = null;
            XElement profile = null;
            XElement recent = null;

            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializer s = new XmlSerializer(typeof(Prefs));
                StreamWriter writer = new StreamWriter(stream);

                s.Serialize(writer, Prefs.Current);
                stream.Position = 0;

                XmlTextReader reader = new XmlTextReader(stream);
                prefs = XElement.Load(reader);
            }

            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializer s = new XmlSerializer(typeof(Profile));
                StreamWriter writer = new StreamWriter(stream);

                s.Serialize(writer, Main.Primary);
                stream.Position = 0;

                XmlTextReader reader = new XmlTextReader(stream);
                profile = XElement.Load(reader);
            }

            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializer s = new XmlSerializer(typeof(RecentFileCollection));
                StreamWriter writer = new StreamWriter(stream);

                s.Serialize(writer, this.RecentFiles);
                stream.Position = 0;

                XmlTextReader reader = new XmlTextReader(stream);
                recent = XElement.Load(reader);
            }

            XDocument doc = new XDocument();

            XElement root = new XElement("MVPlan");

            doc.Add(root);
            root.Add(prefs);
            root.Add(profile);
            root.Add(recent);

            doc.Save(Main.Path);

            this.Title = Main.Path;

            this.RecentFiles.AddPath(Main.Path);

            setRecentFilesList();
        }

        protected string GetSaveFilePath()
        {
            SaveFileDialog save = new SaveFileDialog();

            save.Filter = "(*.xml)|*.xml";

            if (save.ShowDialog(this) == true)
            {
                return save.FileName;
            }
            else
            {
                return null;
            }
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            if (!Main.IsLoaded)
            {
                string path = GetSaveFilePath();

                if (path != null)
                {
                    SaveFile(path);
                }
            }
        }

        public RecentFileCollection RecentFiles { get; set; }
        
        private void btnCalc_Click(object sender, RoutedEventArgs e)
        {
            Progress.IsIndeterminate = true;
            Progress.Visibility = Visibility.Visible;

            Ribbon.IsEnabled = false;            
            Main.Calculate();
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            Main.Reset(false);
        }

        private void btnViewBail_Checked(object sender, RoutedEventArgs e)
        {
            Main.SetView(false);
        }

        private void btnViewBail_Unchecked(object sender, RoutedEventArgs e)
        {
            Main.SetView(true);
        }

        private void btnPrint_Click(object sender, RoutedEventArgs e)
        {
            TableView tv = new TableView();

            tv.Profile = Main.Primary;
            tv.RenderReport();

            tv.Show();
        }

        private void btnViewChart_Click(object sender, RoutedEventArgs e)
        {
            ChartView cv = new ChartView();

            Main.BindChart(cv.Chart, Main.Primary, true);

            if (Main.Primary.HasCCRSegment)
            {
                Main.BindChart(cv.Chart, Main.Bailout, false);
            }

            cv.Show();
        }

        private void btnExcel_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();

            save.Filter = "(*.xls)|*.xls";

            if (save.ShowDialog() == true)
            {
                Workbook w = new Workbook();

                Worksheet sheet = w.Worksheets.Add("Profile");

                sheet.Rows[0].Cells[0].Value = "Waypoint";
                sheet.Rows[0].Cells[1].Value = "Depth";
                sheet.Rows[0].Cells[2].Value = "Time";
                sheet.Rows[0].Cells[3].Value = "Run Time";
                sheet.Rows[0].Cells[4].Value = "Gas";
                sheet.Rows[0].Cells[5].Value = "Mode";
                sheet.Rows[0].Cells[6].Value = "PPO2";
                sheet.Rows[0].Cells[7].Value = "PPN2";
                sheet.Rows[0].Cells[8].Value = "END";
                sheet.Rows[0].Cells[9].Value = "Warnings";

                Profile p = Main.Primary;

                if (!Main.IsPrimaryView)
                {
                    p = Main.Bailout;
                }

                for (int i = 0; i < p.OutputSegments.Count; i++)
                {
                    SegmentAbstract s = p.OutputSegments[i];

                    sheet.Rows[i + 1].Cells[0].Value = s.TypeName;
                    sheet.Rows[i + 1].Cells[1].Value = s.Depth;
                    sheet.Rows[i + 1].Cells[2].Value = s.Time;
                    sheet.Rows[i + 1].Cells[3].Value = s.RunTime;
                    sheet.Rows[i + 1].Cells[4].Value = s.Gas.ToString();
                    sheet.Rows[i + 1].Cells[5].Value = s.Mode;
                    sheet.Rows[i + 1].Cells[6].Value = s.PPO2;
                    sheet.Rows[i + 1].Cells[7].Value = s.PPN2;
                    sheet.Rows[i + 1].Cells[8].Value = s.END;
                    sheet.Rows[i + 1].Cells[9].Value = s.Warnings.ToString();
                }

                w.Save(save.FileName);
            }
        }

        private void btnAbout_Click(object sender, RoutedEventArgs e)
        {
            About a = new About();
            a.ShowDialog();
        }

        private void btnHelp_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("No help is available for this version.");
        }

        private void rdoImperil_Checked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.Units = Units.Imperial;
            Main.Reset(this.ResetData);
        }

        private void rdoImperil_Unchecked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.Units = Units.Metric;
            Main.Reset(this.ResetData);
        }

        #endregion

        #region Settings Events

        int settingsOut;
        double dSettings;

        private void txtGFLow_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
                Prefs.Current.GfLow = e.NewValue.ToDouble() / 100;
        }

        private void txtGFHigh_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.GfHigh = e.NewValue.ToDouble() / 100;
        }

        private void txtGFLowBail_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.GfLowBailout = e.NewValue.ToDouble() / 100;
        }

        private void txtGFHighBail_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.GfHighBailout = e.NewValue.ToDouble() / 100;
        }

        private void txtStopIncrement_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.StopDepthIncrement = e.NewValue.ToDouble();
        }

        private void txtStopLast_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.LastStopDepth = e.NewValue.ToDouble();
        }

        private void txtStopTime_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.StopTimeIncrement = e.NewValue.ToDouble();
        }

        private void txtRMVDive_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.RMVDive = e.NewValue.ToDouble();
        }

        private void txtRMVDeco_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.RMVDeco = e.NewValue.ToDouble();
        }

        private void chkRuntimeFlag_Checked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.RuntimeFlag = true;
        }

        private void chkRuntimeFlag_Unchecked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.RuntimeFlag = false;
        }

        private void txtDescent_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.DescentRate = e.NewValue.ToDouble();
        }

        private void txtAscent_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.AscentRate = -1D * e.NewValue.ToDouble();
        }

        private void txtAltitude_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            //throw new NotSupportedException(); 
        }

        private void txtMaxPPO2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
            {
                Prefs.Current.PPO2Max = e.NewValue.ToDouble();

                if (Main != null && Main.IsLoaded)
                    Main.ResetGases();
            }
        }


        private void txtSetpointDefault_TextChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
                Prefs.Current.SetpointDefault = e.NewValue.ToDouble();
        }

        private void txtWarnLowPPO2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
            Prefs.Current.WarningPPO2Min = e.NewValue.ToDouble();
        }

        private void txtWarnHighPPO2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
            Prefs.Current.WarningPPO2Max = e.NewValue.ToDouble();
        }
        
        private void txtWarnDecoLow_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
            Prefs.Current.WarningOptimalDecoPPO2Min = e.NewValue.ToDouble();
        }

        private void txtWarnDecoHigh_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (double.TryParse(e.NewValue, out dSettings))
            Prefs.Current.WarningOptimalDecoPPO2Max = e.NewValue.ToDouble();
        }

        private void txtWarnPPN2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<string> e)
        {
            if (int.TryParse(e.NewValue, out settingsOut))
            Prefs.Current.WarningPPN2SpikePercentageMin = e.NewValue.ToDouble() / 100;
        }

        private void chkShowBailout_Checked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.ReportShowBailout = true;
        }

        private void chkShowBailout_Unchecked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.ReportShowBailout = false;
        }

        private void chkShowStopTime_Checked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.ReportShowStopTime = true;
        }

        private void chkShowStopTime_Unchecked(object sender, RoutedEventArgs e)
        {
            Prefs.Current.ReportShowStopTime = false;
        }

        #endregion

        private void Main_FileLoaded(object sender, EventArgs e)
        {
            this.Title = Main.Path;
            Initialize();

            this.RecentFiles.AddPath(Main.Path);
            setRecentFilesList();

            btnCalc_Click(null, null);
            this.ResetData = true;
        }

        private void XamRibbonWindow_Unloaded(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void XamRibbonWindow_Loaded(object sender, RoutedEventArgs e)
        {            
            Main.LoadFile(AppDomain.CurrentDomain.BaseDirectory + @"ProfileData\Defaults.xml");

            Main.Visibility = Visibility.Visible;
        }

        private void Main_Calculated(object sender, EventArgs e)
        {
            enableUI();
        }

        private void Main_CalculateFailed(object sender, ProfileStatus status)
        {
            MessageBox.Show("Calc failed: " + status.ToString());
            enableUI();
        }

        private void Main_ValidationFailed(object sender, EventArgs e)
        {
            enableUI();
        }

        private void enableUI()
        {
            Progress.IsIndeterminate = false;
            Progress.Visibility = Visibility.Hidden;

            Ribbon.IsEnabled = true;

            RadioButtonTool btDive = (RadioButtonTool)Ribbon.Tabs[0].RibbonGroups[1].Items[0];
            RadioButtonTool btBail = (RadioButtonTool)Ribbon.Tabs[0].RibbonGroups[1].Items[1];

            btBail.IsEnabled = Main.Primary.HasCCRSegment;

            if (!btBail.IsEnabled)
            {
                btDive.IsChecked = true;
            }
        }

    }
}
